﻿using System;
using System.Collections.Generic;
using System.Linq;
using YArchitech.Controls;

namespace YArchitech.Plumbing
{
	internal class SprayCalculate
	{
		public CalculateType CalType { get; set; }

		public double FixedPressure { get; set; }

		public double SprinklerCoefficient { get; set; }

		public double EffectArea { get; set; }

		public double PartialLossFactor { get; set; }

		public SprayCalculate(HYPipeCal pipe, List<HYSprayNode> nodes)
		{
			this.CalType = CalculateType.CalByCheckTheFirst;
			this.FixedPressure = 5.0;
			this.SprinklerCoefficient = 80.0;
			this.PartialLossFactor = 0.2;
			this.EffectArea = 0.0;
			this.startPipe = pipe;
			this.sprayNodes = nodes;
			if (SprayCalculate.velocityKC.Count == 0)
			{
				SprayCalculate.velocityKC.Add(15.0, 5.85);
				SprayCalculate.velocityKC.Add(20.0, 3.105);
				SprayCalculate.velocityKC.Add(25.0, 1.883);
				SprayCalculate.velocityKC.Add(40.0, 0.8);
				SprayCalculate.velocityKC.Add(50.0, 0.47);
				SprayCalculate.velocityKC.Add(70.0, 0.283);
				SprayCalculate.velocityKC.Add(80.0, 0.204);
				SprayCalculate.velocityKC.Add(100.0, 0.115);
				SprayCalculate.velocityKC.Add(125.0, 0.075);
				SprayCalculate.velocityKC.Add(150.0, 0.053);
			}
		}

		protected double GetSprinklerFlow(double pressure, double coefficient)
		{
			double result = (double)1 * coefficient * Math.Pow(10.0 * pressure / 100.0, 0.5) / 60.0;
			if (pressure < 0.0)
			{
				result = -0.33;
			}
			return result;
		}

		public double GetVelocityKc(double DN)
		{
			double result = 0.0;
			if (SprayCalculate.velocityKC.Count > 0)
			{
				try
				{
					if (!SprayCalculate.velocityKC.TryGetValue(DN, out result))
					{
						result = this.GetDeviationValue(DN);
					}
				}
				catch (Exception ex)
				{
					YJKMessageBox.Show(ex.ToString());
				}
			}
			return result;
		}

		private double GetDeviationValue(double DN)
		{
			double result = 0.0;
			if (SprayCalculate.velocityKC.Count > 0)
			{
				try
				{
					int num = -1;
					foreach (KeyValuePair<double, double> keyValuePair in SprayCalculate.velocityKC)
					{
						result = keyValuePair.Value;
						num++;
						if (keyValuePair.Key > DN)
						{
							break;
						}
					}
					if (num > 0 && num < SprayCalculate.velocityKC.Count)
					{
						KeyValuePair<double, double> keyValuePair2 = SprayCalculate.velocityKC.ElementAt(num);
						KeyValuePair<double, double> keyValuePair3 = SprayCalculate.velocityKC.ElementAt(num - 1);
						result = keyValuePair3.Value - Math.Abs((keyValuePair2.Value - keyValuePair3.Value) / (keyValuePair2.Key - keyValuePair3.Key) * (DN - keyValuePair3.Key));
					}
				}
				catch (Exception ex)
				{
					YJKMessageBox.Show(ex.ToString());
				}
			}
			return result;
		}

		public double GetPipeFlowVelocity(HYPipeCal pipe)
		{
			double num = 0.0;
			try
			{
				num = Math.Abs(pipe.Flow * this.GetVelocityKc((double)pipe.nDN));
			}
			catch (Exception ex)
			{
				ex.ToString();
			}
			pipe.Velocity = num;
			return num;
		}

		public double GetAllPipeLoss(HYPipeCal pipe)
		{
			double pipeFlowVelocity = this.GetPipeFlowVelocity(pipe);
			double inDN = pipe.GetInDN();
			if (inDN > 1.0)
			{
				double num = 1.07E-05 * (Math.Pow(pipeFlowVelocity, 2.0) / Math.Pow((inDN - 1.0) / 1000.0, 1.3));
				pipe.LossPipe = num * pipe.Length;
				double num2 = 0.0;
				foreach (HYFittingCal hyfittingCal in pipe.fittingArray)
				{
					string name = "";
					switch (hyfittingCal.Type)
					{
					case HYFittingCal.eType.Reduce:
						name = EquivalentLength.Transition;
						break;
					case HYFittingCal.eType.Elbow:
						name = EquivalentLength.Elbow;
						break;
					case HYFittingCal.eType.Tee:
						name = EquivalentLength.TeeOrCross;
						break;
					case HYFittingCal.eType.Cross:
						name = EquivalentLength.TeeOrCross;
						break;
					}
					num2 += EquivalentLengthContainer.Instance.GetFittingEquivalentLength(name, pipe.nDN);
				}
				foreach (HYPipeValveCal hypipeValveCal in pipe.valveArray)
				{
					num2 += EquivalentLengthContainer.Instance.GetValveEquivalentLength(hypipeValveCal.Name, pipe.nDN);
				}
				pipe.dEquivalent = num2;
				pipe.LossPart = num * num2;
				pipe.LossAll = pipe.LossPipe + pipe.LossPart;
			}
			return pipe.LossAll;
		}

		public bool SetFixedPressure(CalculateType calType, double pressure)
		{
			bool result = true;
			double num = 0.0;
			HYSprayNode hysprayNode = null;
			foreach (HYSprayNode hysprayNode2 in this.sprayNodes)
			{
				if (calType == CalculateType.CalByCheckTheFirst)
				{
					if (hysprayNode2.sprinkler != null && hysprayNode2.sprinkler.PathLength > num)
					{
						num = hysprayNode2.sprinkler.PathLength;
						hysprayNode = hysprayNode2;
					}
				}
				else if (calType == CalculateType.CalBycheckTheWorst && hysprayNode2.IsStart)
				{
					hysprayNode2.Pressure = pressure;
					hysprayNode2.IsFixedPressure = true;
					break;
				}
			}
			if (hysprayNode != null)
			{
				hysprayNode.sprinkler.Pressure = pressure;
				hysprayNode.sprinkler.IsFixedPress = true;
				hysprayNode.Pressure = pressure;
				hysprayNode.IsFixedPressure = true;
			}
			return result;
		}

		public bool FixWorstPoint()
		{
			return false;
		}

		public bool DefPipeVolAndPressure()
		{
			bool result = true;
			result = this.CalPipeVolAndPressure(this.startPipe);
			this.startPipe.startNode.Pressure = this.startPipe.endNode.Pressure + this.GetAllPipeLoss(this.startPipe);
			this.startPipe.startNode.IsCalculated = true;
			foreach (HYSprayNode hysprayNode in this.sprayNodes)
			{
				if (!hysprayNode.IsStart && hysprayNode.InPipes.Count > 0 && hysprayNode.InPipes[0].Flow > 0.0)
				{
					hysprayNode.IsCalculated = true;
				}
			}
			return result;
		}

		public bool CalPipeVolAndPressure(HYPipeCal previousPipe)
		{
			bool result = false;
			if (previousPipe == null)
			{
				return result;
			}
			foreach (HYPipeCal hypipeCal in previousPipe.subPipeArray)
			{
				if (hypipeCal.endSprinkler != null)
				{
					double num = 0.0;
					double pressure = 0.0;
					if (hypipeCal.endSprinkler.IsInArea)
					{
						pressure = this.FixedPressure;
						hypipeCal.endSprinkler.Pressure = this.FixedPressure;
						num += this.GetSprinklerFlow(hypipeCal.endSprinkler.Pressure, this.SprinklerCoefficient);
					}
					hypipeCal.Flow = num;
					hypipeCal.endNode.FLow = num;
					hypipeCal.endNode.Pressure = pressure;
					hypipeCal.startPress = hypipeCal.endNode.Pressure + this.GetAllPipeLoss(hypipeCal);
				}
				else
				{
					this.CalPipeVolAndPressure(hypipeCal);
				}
				previousPipe.endNode.Pressure += hypipeCal.startPress;
				previousPipe.Flow += hypipeCal.Flow;
			}
			previousPipe.startPress = previousPipe.endNode.Pressure + this.GetAllPipeLoss(previousPipe);
			return result;
		}

		public int SolveNodeEquation()
		{
			int num = 0;
			foreach (HYSprayNode hysprayNode in this.sprayNodes)
			{
				if (!hysprayNode.IsFixedPressure && hysprayNode.IsCalculated)
				{
					hysprayNode.CalculateNum = num;
					num++;
				}
			}
			List<double> list = new List<double>(new double[num]);
			Matrix matrix = new Matrix(num, num);
			matrix.ZeroMatrix();
			foreach (HYSprayNode hysprayNode2 in this.sprayNodes)
			{
				if (!hysprayNode2.IsFixedPressure && hysprayNode2.IsCalculated)
				{
					double num2 = 0.0;
					if (hysprayNode2.sprinkler != null && hysprayNode2.sprinkler.IsInArea)
					{
						num2 = -this.GetSprinklerFlow(hysprayNode2.Pressure, this.SprinklerCoefficient);
					}
					else if (hysprayNode2.IsStart && hysprayNode2.OutPipes.Count > 0)
					{
						num2 = -hysprayNode2.OutPipes[0].Flow;
					}
					int calculateNum = hysprayNode2.CalculateNum;
					double num3 = 0.0;
					foreach (HYPipeCal hypipeCal in hysprayNode2.InPipes)
					{
						if (hypipeCal != null && hypipeCal.startNode != null && (hypipeCal.startNode.IsCalculated || hypipeCal.startNode.IsFixedPressure))
						{
							double allPipeLoss = this.GetAllPipeLoss(hypipeCal);
							double num4 = hypipeCal.Flow / allPipeLoss;
							hypipeCal.dCs = num4;
							int calculateNum2 = hypipeCal.startNode.CalculateNum;
							if (hypipeCal.startNode.IsFixedPressure)
							{
								num2 += num4 * hypipeCal.startNode.Pressure;
							}
							else
							{
								matrix[calculateNum, calculateNum2] = -num4;
							}
							num3 += num4;
						}
					}
					foreach (HYPipeCal hypipeCal2 in hysprayNode2.OutPipes)
					{
						if (hypipeCal2 != null && hypipeCal2.endNode != null && (hypipeCal2.endNode.IsCalculated || hypipeCal2.endNode.IsFixedPressure))
						{
							double allPipeLoss = this.GetAllPipeLoss(hypipeCal2);
							double num4 = hypipeCal2.Flow / allPipeLoss;
							hypipeCal2.dCs = num4;
							int calculateNum2 = hypipeCal2.endNode.CalculateNum;
							if (hypipeCal2.endNode.IsFixedPressure)
							{
								num2 += num4 * hypipeCal2.endNode.Pressure;
							}
							else
							{
								matrix[calculateNum, calculateNum2] = -num4;
							}
							num3 += num4;
						}
					}
					matrix[calculateNum, calculateNum] = num3;
					if (hysprayNode2.IsStart)
					{
						if (hysprayNode2.InPipes.Count + hysprayNode2.OutPipes.Count == 1)
						{
							list[calculateNum] = -num2;
						}
						else
						{
							list[calculateNum] = num2;
						}
					}
					else
					{
						list[calculateNum] = num2;
					}
				}
			}
			if (!Matrix.TotalChoiceGaussElimination(matrix, ref list))
			{
				YJKMessageBox.Error("求解方程组失败！");
				return 2;
			}
			if (this.UpdateNetWork(list))
			{
				return 0;
			}
			return 1;
		}

		public bool UpdateNetWork(List<double> flowArray)
		{
			foreach (HYSprayNode hysprayNode in this.sprayNodes)
			{
				if (!hysprayNode.IsFixedPressure && hysprayNode.IsCalculated)
				{
					int calculateNum = hysprayNode.CalculateNum;
					hysprayNode.Pressure = flowArray[calculateNum] * 0.2 + hysprayNode.Pressure * 0.8;
				}
			}
			double num = 0.0;
			HYSprayNode hysprayNode2 = null;
			foreach (HYSprayNode hysprayNode3 in this.sprayNodes)
			{
				if (hysprayNode3.IsStart)
				{
					hysprayNode2 = hysprayNode3;
				}
				if (hysprayNode3.IsCalculated)
				{
					if (hysprayNode3.sprinkler != null && hysprayNode3.sprinkler.IsInArea)
					{
						num += this.GetSprinklerFlow(hysprayNode3.Pressure, this.PartialLossFactor);
					}
					else
					{
						hysprayNode3.FLow = 0.0;
					}
				}
			}
			if (hysprayNode2 != null)
			{
				hysprayNode2.FLow = num;
			}
			int num2 = 0;
			int num3 = 0;
			foreach (HYSprayNode hysprayNode4 in this.sprayNodes)
			{
				foreach (HYPipeCal hypipeCal in hysprayNode4.InPipes)
				{
					double flow = hypipeCal.Flow;
					double num4 = hypipeCal.dCs * Math.Abs(hypipeCal.endNode.Pressure - hypipeCal.startNode.Pressure);
					hypipeCal.Flow = 0.5 * (flow + num4);
					hypipeCal.startPress = hypipeCal.startNode.Pressure;
					this.GetPipeFlowVelocity(hypipeCal);
					if (Math.Abs(flow - num4) < 0.0001)
					{
						num2++;
					}
					num3++;
				}
				foreach (HYPipeCal hypipeCal2 in hysprayNode4.OutPipes)
				{
					double flow = hypipeCal2.Flow;
					double num4 = hypipeCal2.dCs * Math.Abs(hypipeCal2.endNode.Pressure - hypipeCal2.startNode.Pressure);
					hypipeCal2.Flow = 0.5 * (flow + num4);
					hypipeCal2.startPress = hypipeCal2.startNode.Pressure;
					this.GetPipeFlowVelocity(hypipeCal2);
					if (Math.Abs(flow - num4) < 0.0001)
					{
						num2++;
					}
					num3++;
				}
			}
			return num2 == num3;
		}

		public string GetResult()
		{
			HYSprayNode hysprayNode = null;
			HYSprayNode hysprayNode2 = null;
			double num = 0.0;
			foreach (HYSprayNode hysprayNode3 in this.sprayNodes)
			{
				if (hysprayNode3.IsStart)
				{
					hysprayNode2 = hysprayNode3;
				}
				if (hysprayNode3.sprinkler != null && hysprayNode3.sprinkler.PathLength > num)
				{
					num = hysprayNode3.sprinkler.PathLength;
					hysprayNode = hysprayNode3;
				}
			}
			double num2 = 0.0;
			if (hysprayNode != null)
			{
				HYPipeCal hypipeCal = hysprayNode.InPipes[0];
				num2 += hysprayNode.Pressure;
				num2 += this.GetAllPipeLoss(hypipeCal) * 100.0;
				for (HYPipeCal perviousPipe = hypipeCal.perviousPipe; perviousPipe != null; perviousPipe = perviousPipe.perviousPipe)
				{
					num2 += this.GetAllPipeLoss(perviousPipe) * 100.0;
				}
			}
			string arg = "";
			if (this.EffectArea > 0.0)
			{
				arg = (60.0 * hysprayNode2.OutPipes[0].Flow / this.EffectArea).ToString("f3");
			}
			string result;
			if (this.CalType == CalculateType.CalBycheckTheWorst)
			{
				result = string.Format("最不利点水压(m.H2O): {0}, 总流量(L/s): {1}, 平均喷水强度(L/min.m^2): {2}", hysprayNode.Pressure.ToString("f2"), hysprayNode2.OutPipes[0].Flow.ToString("f2"), arg);
			}
			else
			{
				result = string.Format("入口压力(m.H2O): {0}, 总流量(L/s): {1}, 平均喷水强度(L/min.m^2): {2}", hysprayNode2.Pressure.ToString("f2"), hysprayNode2.OutPipes[0].Flow.ToString("f2"), arg);
			}
			return result;
		}

		protected bool UpdateNodesPressure(HYPipeCal previousPipe)
		{
			bool result = false;
			if (previousPipe == null)
			{
				return result;
			}
			if (previousPipe.endSprinkler == null)
			{
				previousPipe.endNode.Pressure = 0.0;
			}
			foreach (HYPipeCal hypipeCal in previousPipe.subPipeArray)
			{
				if (hypipeCal.endSprinkler != null)
				{
					if (hypipeCal.endSprinkler.IsInArea)
					{
						hypipeCal.startPress = hypipeCal.endNode.Pressure + this.GetAllPipeLoss(hypipeCal) * 100.0;
					}
				}
				else
				{
					this.UpdateNodesPressure(hypipeCal);
				}
				previousPipe.endNode.Pressure += hypipeCal.startPress;
			}
			previousPipe.startPress = previousPipe.endNode.Pressure + this.GetAllPipeLoss(previousPipe) * 100.0;
			return result;
		}

		public bool SolveAccumulateMethod()
		{
			int num = 0;
			HYSprayNode hysprayNode = null;
			HYSprayNode hysprayNode2 = null;
			foreach (HYSprayNode hysprayNode3 in this.sprayNodes)
			{
				if (hysprayNode3.IsStart)
				{
					hysprayNode2 = hysprayNode3;
				}
				if (hysprayNode3.IsFixedPressure)
				{
					hysprayNode = hysprayNode3;
				}
				else
				{
					hysprayNode3.CalculateNum = num;
					num++;
				}
			}
			if (hysprayNode == null || hysprayNode2 == null)
			{
				return false;
			}
			if (this.CalType == CalculateType.CalBycheckTheWorst)
			{
				hysprayNode2.Pressure = this.FixedPressure;
				this.CalculateNodePress(hysprayNode2.OutPipes[0]);
			}
			hysprayNode.FLow = this.GetSprinklerFlow(hysprayNode.Pressure, this.SprinklerCoefficient);
			this.CaleNodeForward(hysprayNode, null);
			return true;
		}

		private bool CaleNodeForward(HYSprayNode node, HYSprayNode finallyNode)
		{
			if (node.IsStart)
			{
				return true;
			}
			if (node.InPipes.Count < 1 || node.InPipes[0].startNode == null)
			{
				return false;
			}
			HYPipeCal hypipeCal = node.InPipes[0];
			hypipeCal.Flow = node.FLow;
			this.CalPipe(hypipeCal);
			HYSprayNode startNode = hypipeCal.startNode;
			startNode.Pressure = node.Pressure + hypipeCal.LossAll * 100.0;
			if (finallyNode != null && startNode == finallyNode)
			{
				return true;
			}
			startNode.FLow = 0.0;
			int count = startNode.OutPipes.Count;
			if (count != 1)
			{
				if (count - 2 <= 1)
				{
					foreach (HYPipeCal hypipeCal2 in startNode.OutPipes)
					{
						if (hypipeCal2 != hypipeCal)
						{
							this.CalculateNodePress(hypipeCal2);
						}
						startNode.FLow += hypipeCal2.Flow;
					}
					this.CaleNodeForward(startNode, finallyNode);
				}
			}
			else
			{
				startNode.FLow = hypipeCal.Flow;
				this.CaleNodeForward(startNode, finallyNode);
			}
			return true;
		}

		private bool CalculateNodePress(HYPipeCal pipe)
		{
			HYSprayNode startNode = pipe.startNode;
			double pressure = startNode.Pressure;
			HYSprayNode lengthSprayNode = this.GetLengthSprayNode(pipe);
			if (lengthSprayNode == null)
			{
				return false;
			}
			int num = 2;
			double num2 = this.FixedPressure;
			double num3 = -1.0;
			double num4 = -1.0;
			int num5 = 1;
			while (num != 0 && num5 <= 100)
			{
				lengthSprayNode.FLow = this.GetSprinklerFlow(num2, this.SprinklerCoefficient);
				lengthSprayNode.Pressure = num2;
				this.CaleNodeForward(lengthSprayNode, startNode);
				if (Math.Abs(startNode.Pressure - pressure) < 0.001)
				{
					num = 0;
				}
				else if (startNode.Pressure > pressure)
				{
					if (num2 < num3 || num3 < 0.0)
					{
						num3 = num2;
					}
					if (num4 < 0.0)
					{
						num2 /= 2.0;
					}
					else
					{
						num2 = (num2 + num4) / 2.0;
					}
					num = 1;
				}
				else
				{
					if (num2 > num4)
					{
						num4 = num2;
					}
					if (num3 > 0.0)
					{
						num2 = (num2 + num3) / 2.0;
					}
					else
					{
						num2 *= 2.0;
					}
					num = -1;
				}
				num5++;
			}
			return true;
		}

		private HYSprayNode GetLengthSprayNode(HYPipeCal pipe)
		{
			if (pipe == null || pipe.endNode == null)
			{
				return null;
			}
			Dictionary<HYSprayNode, double> dictionary = new Dictionary<HYSprayNode, double>();
			double num = 0.0;
			this.GetNextLength(pipe, ref dictionary, num);
			if (dictionary.Count < 1)
			{
				return null;
			}
			num = 0.0;
			HYSprayNode result = null;
			foreach (KeyValuePair<HYSprayNode, double> keyValuePair in dictionary)
			{
				if (keyValuePair.Value > num)
				{
					num = keyValuePair.Value;
					result = keyValuePair.Key;
				}
			}
			return result;
		}

		private bool GetNextLength(HYPipeCal pipe, ref Dictionary<HYSprayNode, double> dicFullLong, double dLength)
		{
			if (pipe == null || pipe.endNode == null)
			{
				return false;
			}
			dLength += pipe.Length;
			if (pipe.endNode.sprinkler != null && pipe.endNode.sprinkler.IsInArea)
			{
				dicFullLong.Add(pipe.endNode, dLength);
			}
			foreach (HYPipeCal pipe2 in pipe.endNode.OutPipes)
			{
				this.GetNextLength(pipe2, ref dicFullLong, dLength);
			}
			return true;
		}

		protected double GetNodeK(double pressure, double flow)
		{
			return 60.0 * flow / Math.Pow(10.0 * pressure / 100.0, 0.5);
		}

		private bool CalPipe(HYPipeCal pipe)
		{
			this.GetAllPipeLoss(pipe);
			if (this.checkOption == 1)
			{
				if (pipe.Velocity > 5.0 && this.addSpecDiameter(pipe))
				{
					this.GetAllPipeLoss(pipe);
				}
			}
			else if (this.checkOption == 2)
			{
				while (pipe.Velocity > 5.0 && this.addSpecDiameter(pipe))
				{
					this.GetAllPipeLoss(pipe);
				}
			}
			return true;
		}

		private bool addSpecDiameter(HYPipeCal pipe)
		{
			int num = int.MaxValue;
			foreach (KeyValuePair<int, double> keyValuePair in pipe.dirDNArray)
			{
				if (keyValuePair.Key > pipe.nDN && keyValuePair.Key < num)
				{
					num = keyValuePair.Key;
				}
			}
			if (num == 2147483647)
			{
				return false;
			}
			pipe.nDN = num;
			return true;
		}

		public HYPipeCal startPipe;

		public List<HYSprayNode> sprayNodes;

		public static readonly Dictionary<double, double> velocityKC = new Dictionary<double, double>();

		public int checkOption;
	}
}
